/*
 * Copyright 2012 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package io.netty.channel;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.util.UncheckedBooleanSupplier;
import io.netty.util.internal.UnstableApi;

import static io.netty.util.internal.ObjectUtil.checkNotNull;

/**
 * 分配一个新的 receive buffer, 其容量可能足够大以读取所有 inbound 数据, 同时足够小而不会浪费空间.
 */
public interface RecvByteBufAllocator {

    /**
     * 创建一个新的 handle.
     * <p>
     * 该 handle 提供实际操作, 并保留预测最佳 buffer 容量所需的内部信息.
     */
    Handle newHandle();

    /**
     * @deprecated Use {@link ExtendedHandle}.
     */
    @Deprecated
    interface Handle {

        /**
         * 创建一个新的 receive buffer, 其容量可能足够大以读取所有 inbound 数据, 同时又足够小而不会浪费其空间
         */
        ByteBuf allocate(ByteBufAllocator alloc);

        /**
         * 类似于 {@link #allocate(ByteBufAllocator)}, 除了它不分配任何内容, 仅告知容量
         */
        int guess();

        /**
         * 重置所有已经累积的计数器, 推荐下一 read loop 应该读取 messages/byte 数量
         * <p>
         * 该方法可能被 {@link #continueReading()} 使用以确定 read 操作应该完成完成
         * </p>
         * 这只是一个提示, 可能会被实现忽略.
         *
         * @param config 可能会影响该对象行为的 channel 配置
         */
        void reset(ChannelConfig config);

        /**
         * 增加当前 read loop 已读取的 messages 数量
         *
         * @param numMessages The amount to increment by.
         */
        void incMessagesRead(int numMessages);

        /**
         * 设置上一次读取操作已读取的 byte 数. 这可用于增加已读取的 byte 数
         *
         * @param bytes 上次 read 操作的字节数.
         *              如果发生读取错误, 该值可能为负.
         *              如果看到负值, 则预期在下一次调用 {@link #lastBytesRead()} 时, 返回该值.
         *              负值表示终止条件在此类外部强制执行, 并且不需要在 {@link #continueReading()} 中强制执行.
         */
        void lastBytesRead(int bytes);

        /**
         * 获取上一次读取操作已读取的 byte 数.
         */
        int lastBytesRead();

        /**
         * 设置 read 操作将尝试(或已尝试)读取的字节数
         *
         * @param bytes How many bytes the read operation will (or did) attempt to read.
         */
        void attemptedBytesRead(int bytes);

        /**
         * 获取 read 操作将尝试(或已尝试)读取的字节数
         *
         * @return How many bytes the read operation will (or did) attempt to read.
         */
        int attemptedBytesRead();

        /**
         * 确定当前的 read loop 是否应该继续
         *
         * @return {@code true}: read loop 应该继续读取; {@code false}: read loop 已经完成
         */
        boolean continueReading();

        /**
         * read 已经完成
         */
        void readComplete();
    }

    @SuppressWarnings("deprecation")
    @UnstableApi
    interface ExtendedHandle extends Handle {

        /**
         * 与 {@link Handle#continueReading()} 相同, 只不过是否读取"更多数据"由 supplier 参数确定
         *
         * @param maybeMoreDataSupplier 确定是否可能需要读取更多数据的 supplier
         */
        boolean continueReading(UncheckedBooleanSupplier maybeMoreDataSupplier);
    }

    /**
     * 将所有调用委托给其它 {@link Handle} 的 {@link Handle}
     */
    class DelegatingHandle implements Handle {

        private final Handle delegate;

        public DelegatingHandle(Handle delegate) {
            this.delegate = checkNotNull(delegate, "delegate");
        }

        /**
         * 被委托的 {@link Handle}
         */
        protected final Handle delegate() {
            return delegate;
        }

        @Override
        public ByteBuf allocate(ByteBufAllocator alloc) {
            return delegate.allocate(alloc);
        }

        @Override
        public int guess() {
            return delegate.guess();
        }

        @Override
        public void reset(ChannelConfig config) {
            delegate.reset(config);
        }

        @Override
        public void incMessagesRead(int numMessages) {
            delegate.incMessagesRead(numMessages);
        }

        @Override
        public void lastBytesRead(int bytes) {
            delegate.lastBytesRead(bytes);
        }

        @Override
        public int lastBytesRead() {
            return delegate.lastBytesRead();
        }

        @Override
        public boolean continueReading() {
            return delegate.continueReading();
        }

        @Override
        public int attemptedBytesRead() {
            return delegate.attemptedBytesRead();
        }

        @Override
        public void attemptedBytesRead(int bytes) {
            delegate.attemptedBytesRead(bytes);
        }

        @Override
        public void readComplete() {
            delegate.readComplete();
        }
    }
}
